package com.platform.modules.wallet.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.platform.common.constant.AppConstants;
import com.platform.common.exception.BaseException;
import com.platform.common.utils.redis.RedisUtils;
import com.platform.common.web.service.impl.BaseServiceImpl;
import com.platform.modules.chat.domain.ChatFriend;
import com.platform.modules.chat.domain.ChatGroup;
import com.platform.modules.chat.domain.ChatMsg;
import com.platform.modules.chat.domain.ChatUser;
import com.platform.modules.chat.service.ChatFriendService;
import com.platform.modules.chat.service.ChatGroupService;
import com.platform.modules.chat.service.ChatUserService;
import com.platform.modules.push.enums.PushMsgTypeEnum;
import com.platform.modules.push.service.ChatPushService;
import com.platform.modules.push.vo.PushParamVo;
import com.platform.modules.wallet.dao.WalletRedPacketSubDao;
import com.platform.modules.wallet.domain.Wallet;
import com.platform.modules.wallet.domain.WalletAccount;
import com.platform.modules.wallet.domain.WalletRedPacket;
import com.platform.modules.wallet.domain.WalletRedPacketSub;
import com.platform.modules.wallet.enums.*;
import com.platform.modules.wallet.service.WalletAccountService;
import com.platform.modules.wallet.service.WalletRedPacketService;
import com.platform.modules.wallet.service.WalletRedPacketSubService;
import com.platform.modules.wallet.service.WalletService;
import com.platform.modules.wallet.vo.AccountVo01;
import com.platform.modules.wallet.vo.RedPacketSubVo;
import com.platform.modules.wallet.vo.RedPacketSubVo01;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Calendar;
import java.util.Comparator;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service("walletRedPacketSubService")
public class WalletRedPacketServiceSubImpl extends BaseServiceImpl<WalletRedPacketSub> implements WalletRedPacketSubService {

    @Autowired
    private RedisUtils redisUtils;
    @Resource
    private WalletService walletService;
    @Resource
    private WalletRedPacketSubDao walletRedPacketSubDao;
    @Resource
    private WalletAccountService walletAccountService;
    @Resource
    private WalletRedPacketService walletRedPacketService;
    @Resource
    private ChatPushService chatPushService;
    @Resource
    private ChatGroupService groupService;
    @Resource
    private ChatUserService chatUserService;
    @Resource
    private ChatFriendService friendService;

    @Autowired
    public void setBaseDao() {
        super.setBaseDao(walletRedPacketSubDao);
    }

    @Override
    public WalletRedPacketSub createRedPacketSub(RedPacketSubVo vo) {

        WalletRedPacketSub bean = getBean();
        bean.setRedPacketId(vo.getRedpacketId());
        bean.setAmount(vo.getAmount());
        bean.setFromId(vo.getFromId());
        bean.setBestLuck(vo.getBestLuck());
        add(bean);
        return bean;
    }


    public List<WalletRedPacketSub> queryByRedRacketId(Long redPacketId) {

        return new WalletRedPacketSub().selectList(new LambdaQueryWrapper<WalletRedPacketSub>().eq(WalletRedPacketSub::getRedPacketId, redPacketId));
    }

    public Long getSmall(Long repacketId) {
        List<WalletRedPacketSub> list = queryByRedRacketId(repacketId);
        WalletRedPacketSub min = list.stream().min(Comparator.comparing(WalletRedPacketSub::getAmount)).get();
        return min.getId();
    }

    public List<WalletRedPacketSub> queryByToId(Long redPacketId, Long toId) {

        return new WalletRedPacketSub().selectList(new LambdaQueryWrapper<WalletRedPacketSub>().eq(WalletRedPacketSub::getRedPacketId, redPacketId).eq(WalletRedPacketSub::getToId, toId));
    }

    @Override
    public List<WalletRedPacketSub> queryByStatus(Long redPacketId, RedPacketStatusEnum statusEnum) {

        return new WalletRedPacketSub().selectList(new LambdaQueryWrapper<WalletRedPacketSub>().eq(WalletRedPacketSub::getRedPacketId, redPacketId).eq(WalletRedPacketSub::getStatus, statusEnum));
    }

    @Override
    public List<WalletRedPacketSub> queryByStatusSuccess(Long redPacketId) {
        return queryByStatus(redPacketId, RedPacketStatusEnum.SUCCESS);
    }

    @Override
    public List<WalletRedPacketSub> queryByStatusInit(Long redPacketId) {
        return queryByStatus(redPacketId, RedPacketStatusEnum.INIT);
    }

    @Transactional
    @Override
    public RedPacketSubVo01 openRedPacket(Long redPacketId, Long userId) {

        Wallet wallet = walletService.getWallet(userId);

        List<WalletRedPacketSub> walletRedPacketSubs = queryByToId(redPacketId, userId);
        if (walletRedPacketSubs.size() > 0) {
            throw new BaseException("该红包已经抢过了");
        }

        String key = AppConstants.WALLET_RED_PACKET + redPacketId;
        Long expire = redisUtils.getExpire(key);

        WalletRedPacketSub walletRedPacketSub = null;

        //todo 判断用户是否需要获取最佳
        if (OpenNoEnum.YES_LUCK.equals(wallet.getOpenNo())) {
            walletRedPacketSub = walletRedPacketService.getLuck(redPacketId);
        }

        synchronized (this) {
            if (ObjectUtil.isNotEmpty(walletRedPacketSub)) {
                //去掉最佳的元素
                redisUtils.sRemove(key, walletRedPacketSub.getId());
            } else if (expire != -2) {
                if (!redisUtils.hasKey(key)) {
                    throw new BaseException("手慢了，红包派完了");
                }
                if (redisUtils.sSize(key).intValue() == 0) {
                    throw new BaseException("手慢了，红包派完了");
                }
                String spopId = redisUtils.sPop(key);
                walletRedPacketSub = getById(Long.parseLong(spopId));
                if (OpenNoEnum.NO_SMALL.equals(wallet.getOpenNo())) {
                    Long small = getSmall(redPacketId);
                    if (walletRedPacketSub.getId().equals(small)) {
                        redisUtils.sAdd(key, String.valueOf(walletRedPacketSub.getId()));
                        throw new BaseException("系统限制，请重试");
                    }
                } else if (OpenNoEnum.NO_LUCK.equals(wallet.getOpenNo())) {
                    WalletRedPacket redPacket = walletRedPacketService.getById(redPacketId);
                    if (redPacket.getCount() != 1) {
                        if (RedPacketLuckEnum.YES.equals(walletRedPacketSub.getBestLuck())) {
                            redisUtils.sAdd(key, String.valueOf(walletRedPacketSub.getId()));
                            throw new BaseException("系统限制，请重试");
                        }
                    }
                }
            } else {
                List<WalletRedPacketSub> walletRedPacketSubList = walletRedPacketService.querySubInitList(redPacketId);
                if (walletRedPacketSubList.size() > 0) {//判断还没有未领取红包
                    walletRedPacketSub = walletRedPacketSubList.get(0);
                } else {
                    throw new BaseException("手慢了，红包派完了");
                }

                //相差5秒
                long betweenSecond = DateUtil.between(walletRedPacketSub.getCreateTime(), DateUtil.date(), DateUnit.SECOND);
                if (betweenSecond < 5) {
                    throw new BaseException("手慢了，红包派完了");
                }
            }
        }
        if (RedPacketSubStatusEnum.INIT.equals(walletRedPacketSub.getStatus())) {

            successOpen(walletRedPacketSub.getId(), userId);//完成收
            AccountVo01 accountVo = new AccountVo01();
            accountVo.setOtherId(walletRedPacketSub.getId());
            accountVo.setAmount(walletRedPacketSub.getAmount());
            accountVo.setType(AccountTypeEnum.RED_PACKET_IN);
            accountVo.setUserId(userId);

            WalletAccount account = walletAccountService.createRecord(accountVo);//创建账本记录
            walletAccountService.successRecord(account.getId());//完成账本记录
//            walletService.add(accountVo.getAmount(), account.getUserId());//加余额
            successStatus(walletRedPacketSub.getId());//完成入
            walletRedPacketSub.setToId(userId);

            WalletRedPacket redPacket = walletRedPacketService.findById(redPacketId);

            RedPacketSubVo01 convert = Convert.convert(RedPacketSubVo01.class, walletRedPacketSub);

            if (RedPacketTypeEnum.SINGLE.equals(redPacket.getType())) {

                ChatUser to = chatUserService.getById(walletRedPacketSub.getToId());
                String content = StrUtil.format(AppConstants.RED_PACKET_RECEIVE_NOTICE, to.getNickName());

                ChatFriend friend = friendService.getFriend(walletRedPacketSub.getFromId(), walletRedPacketSub.getToId());
                // 发送通知
                chatPushService.pushMsg(ChatUser.initParam(to).setContent(content).setToId(walletRedPacketSub.getFromId()).setTop(friend.getTop()), PushMsgTypeEnum.ALERT);
                ChatUser from = chatUserService.getById(walletRedPacketSub.getFromId());

                friend = friendService.getFriend(walletRedPacketSub.getToId(), walletRedPacketSub.getFromId());
                chatPushService.pushMsg(ChatUser.initParam(from).setContent(content).setToId(walletRedPacketSub.getToId()).setTop(friend.getTop()), PushMsgTypeEnum.ALERT);
            } else {

                // 查询群组
//                ChatGroup group = groupService.getById(redPacket.getToId());

//                ChatUser to = chatUserService.getById(walletRedPacketSub.getToId());
//                String content = StrUtil.format(AppConstants.RED_PACKET_RECEIVE_NOTICE, to.getNickName());
                // 查询群列表
//                ChatMsg chatMsg = new ChatMsg().setToId(redPacket.getToId()).setContent(content);
//                List<PushParamVo> userList = groupService.queryFriendPushFrom(chatMsg);
                // 群信息
//                PushParamVo groupUser = new PushParamVo().setUserId(group.getId()).setNickName(group.getName()).setPortrait(group.getPortrait());
                // 推送
//                    chatPushService.pushMsg(userList, groupUser, PushMsgTypeEnum.RED_PACKET);
            }

            return convert;
        }

        throw new BaseException("红包已经抢完了");
    }

    @Override
    public List<WalletRedPacketSub> getRefun() {

        DateTime date = DateUtil.date();
        return new WalletRedPacketSub().selectList(new LambdaQueryWrapper<WalletRedPacketSub>().eq(WalletRedPacketSub::getStatus, TransferStatusEnum.INIT).eq(WalletRedPacketSub::getInStatus, TransferInEnum.INIT).le(WalletRedPacketSub::getRefundableTime, date));
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void refund(Long id) {
        WalletRedPacketSub sub = findById(id);
        if (!RedPacketSubStatusEnum.INIT.equals(sub.getStatus())) {
            throw new BaseException("订单状态已完成收、入");
        }
        if (!RedPacketSubInEnum.INIT.equals(sub.getInStatus())) {
            throw new BaseException("订单状态接收已完成");
        }

        DateTime date = DateUtil.date();
        sub.setStatus(RedPacketSubStatusEnum.REFUND);
        sub.setRefundTime(date);
        sub.setUpdateTime(date);
        updateById(sub);


        AccountVo01 accountVo = new AccountVo01();
        accountVo.setOtherId(sub.getId());
        accountVo.setAmount(sub.getAmount());
        accountVo.setType(AccountTypeEnum.REFUND);
        accountVo.setUserId(sub.getFromId());

        WalletAccount account = walletAccountService.createRecord(accountVo);
        walletAccountService.successRecord(account.getId());//完成账本记录
//        walletService.add(accountVo.getAmount(), account.getUserId());//加余额 完成入
    }

    @Override
    public Integer clearRecord(String beforeToday) {
        return walletRedPacketSubDao.clearRecord(beforeToday);
    }

    @Override
    public Integer querySumAll() {
        return walletRedPacketSubDao.querySumAll();
    }

    /**
     * 完成接收红包
     *
     * @param id
     */
    private void successOpen(Long id, Long userId) {

        WalletRedPacketSub sub = findById(id);
        sub.setToId(userId);
        DateTime date = DateUtil.date();
        sub.setReceiveTime(date);
        sub.setUpdateTime(date);
        sub.setInStatus(RedPacketSubInEnum.SUCCESS);//完成收
        updateById(sub);
    }

    private void successStatus(Long id) {

        WalletRedPacketSub sub = findById(id);
        DateTime date = DateUtil.date();
        sub.setSuccessTime(date);
        sub.setUpdateTime(date);
        sub.setStatus(RedPacketSubStatusEnum.SUCCESS);
        updateById(sub);
    }

    private WalletRedPacketSub getBean() {
        DateTime date = DateUtil.date();
        return new WalletRedPacketSub()
                .setStatus(RedPacketSubStatusEnum.INIT)
                .setInStatus(RedPacketSubInEnum.INIT)
                .setBestLuck(RedPacketLuckEnum.NO)
                .setCreateDate(date)
                .setCreateTime(date)
                .setRefundableTime(DateUtil.offsetHour(date, 6));
    }
}
